package app

import (
	"cade/src/core"
	"cade/src/core/evtmgr"
	"cade/src/core/log"
	"cade/src/game/app/gconst"
	"cade/src/game/msg"
	"time"
)

// ============================================================================

const (
	C_heartbeat_check_itv = 300 // in seconds
)

// ============================================================================

type Player struct {
	core.Timerable

	user *User
	sid  uint64

	msgq chan func()
	quit chan int

	hb_ts time.Time // 上次心跳时间
}

// ============================================================================

func NewPlayer(on_create func(*User)) *Player {
	// new
	plr := &Player{
		msgq: make(chan func(), 10000),
		quit: make(chan int),
	}

	plr.user = &User{}
	on_create(plr.user)

	// set timerable parent
	plr.SetParent(plr)

	// push heartbeat checker
	plr.Push(func() {
		plr.heartbeat_checker()
	})

	// ok
	return plr
}

// ============================================================================
// 玩家处理协程

func (self *Player) Push(f func()) {
	defer func() { recover() }()

	select {
	case self.msgq <- f:
	default:
		log.Error("player msgq FULL. push discarded")
	}
}

func (self *Player) run(done func()) {
	go func() {
		defer func() {
			close(self.msgq)
			done()
		}()

		for {
			select {
			case <-self.quit:
				return

			case f := <-self.msgq:
				core.PCall(f)
			}
		}
	}()
}

func (self *Player) stop() {
	close(self.quit)
}

// ============================================================================
// 核心功能

func (self *Player) open() {
}

func (self *Player) close() {
}

func (self *Player) send_user_info() {
	self.SendMsg(&msg.GS_UserInfo{
		UserId:   self.user.Id,
		UserName: self.user.Name,
	})
}

func (self *Player) OnOnline() {
	log.Info(self.user.Id, self.user.Name, "is online")

	// update hearbeat
	self.hb_ts = time.Now()

	// fire
	evtmgr.Fire(gconst.Evt_LoginOnline, self, self.user.LoginIP)

	// send user-info
	self.send_user_info()
}

func (self *Player) OnOffline(shutdown bool) {
	if !shutdown {
		log.Info(self.user.Id, self.user.Name, "is offline")
		evtmgr.Fire(gconst.Evt_LoginOffline, self)
	}
}

func (self *Player) IsOnline() bool {
	return self.sid != 0
}

func (self *Player) Sid() uint64 {
	return self.sid
}

func (self *Player) User() *User {
	return self.user
}

func (self *Player) SendMsg(message msg.Message) {
	if self.IsOnline() {
		NetMgr.Send2Player(self.sid, message)
	}
}

func (self *Player) Logout() {
	sid := self.sid

	PlayerMgr.SetOffline(self, false)
	NetMgr.Send2Gate(sid_to_gateid(sid), &msg.GS_Kick{Sid: sid})
}

func (self *Player) HeartbeatUpdate() {
	self.hb_ts = time.Now()
}

func (self *Player) check_heartbeat() {
	if !self.IsOnline() {
		return
	}

	if time.Since(self.hb_ts).Seconds() > 60 {
		self.Logout()
	}
}

// ============================================================================
// 基础接口

func (self *Player) GetId() string {
	return self.user.Id
}

func (self *Player) GetName() string {
	return self.user.Name
}

func (self *Player) GetLoginTs() time.Time {
	return self.user.LoginTs
}

func (self *Player) GetLoginIP() string {
	return self.user.LoginIP
}

// ============================================================================
// 卸载

func (self *Player) heartbeat_checker() {
	self.SetTimeout(time.Now().Add(time.Minute*C_heartbeat_check_itv), func() {
		// check heart-beat: just to avoid very long time suspending
		self.check_heartbeat()
	})
}

// ============================================================================
// chat

func (self *Player) GetChatroomId() int32 {
	return self.user.ChatRoomId
}

func (self *Player) SetChatroomId(id int32) {
	self.user.ChatRoomId = id
}
